using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics.Contracts;

namespace Konst3d.Efficiency.IO
{
    public/*internal*/ class BinaryFile: IDisposable
    {
        #region Properties

        public virtual string FileName
        {
            get
            {
                return _stream.Name;
            }
        }

        #endregion // Properties

        #region Constructors/Finalizer

        public BinaryFile(FileStream stream):
            this(stream, Encoding.UTF8)
        {
        }

        public BinaryFile(FileStream stream, Encoding encoding):
            this(stream, new BinaryReader(stream, encoding), new BinaryWriter(stream, encoding))
        {
        }

        public BinaryFile(FileStream stream, BinaryReader reader, BinaryWriter writer)
        {
            Contract.Requires(stream != null);
            Contract.Requires(reader != null);
            Contract.Requires(writer != null);

            _stream = stream;
            _reader = reader;
            _writer = writer;
        }

        public BinaryFile(FileStream stream, BinaryReader reader, BinaryWriter writer, uint signature, uint version)
        {
            Contract.Requires(stream != null);
            Contract.Requires(reader != null);
            Contract.Requires(writer != null);

            _stream = stream;
            _reader = reader;
            _writer = writer;

            _stream.Seek(0, SeekOrigin.Begin);

            #region Read & Check Signature

            uint sign = _reader.ReadUInt32();

            if (sign != signature)
            {
                throw new IOException(String.Format("Invalid signature in {0}, expected {1}, got {2}.", FileName, signature, sign));
            }

            #endregion // Read & Check Signature

            #region Read & Check Version

            uint ver = _reader.ReadUInt32();

            if (ver != version)
            {
                throw new IOException(String.Format("Invalid version in {0}, expected {1}, got {2}.", FileName, version, ver));
            }

            #endregion // Read & Check Version
        }

        ~BinaryFile()
        {
            Dispose(false);
        }

        #endregion // Constructors/Finalizer

        #region Public Methods

        public virtual void Delete()
        {
            Contract.Assert(!_disposed);

            _stream.Close();
            File.Delete(FileName);

            Dispose();
        }

        #endregion // Public Methods

        #region IDisposable Members

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            Dispose(true);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                DisposeInternal(disposing);
                _disposed = true;
            }
        }

        protected virtual void DisposeInternal(bool disposing)
        {
            if (disposing)
            {
                _reader.Dispose();
                _reader = null;

                _writer.Dispose();
                _writer = null;

                _stream.Dispose();
                _stream = null;
            }
        }

        #endregion

        #region Fields

        protected bool _disposed = false;
        protected FileStream _stream;
        protected BinaryReader _reader;
        protected BinaryWriter _writer;

        #endregion // Fields
    }
}
